﻿using System;
using System.Collections.Generic;
using System.Linq;
using MinecraftEnchantCalculator.Abstractions;
using MinecraftEnchantCalculator.Data.Entity;

namespace MinecraftEnchantCalculator.Core;

/// <summary>
///   附魔物品的抽象基类，实现了
///   <IEnchantable>
///     接口的基础功能
///     提供附魔物品的合并逻辑、铁砧使用次数管理及成本计算等核心功能
/// </summary>
public abstract class AbstractEnchant : IEnchantable
{
  /// <summary>
  ///   铁砧使用次数，用于计算合并时的累计消耗
  ///   每次合并操作后会递增，影响后续合并的成本计算
  /// </summary>
  public int AnvilUseCount { get; private set; }

  /// <summary>
  ///   当前物品的附魔总成本
  ///   基于铁砧使用次数、合并的附魔属性等计算得出
  /// </summary>
  public int Cost { get; private set; }

  /// <summary>
  ///   物品上已有的附魔列表
  ///   存储当前物品携带的所有附魔属性及其等级信息
  /// </summary>
  public List<Enchantment> Enchantments { get; } = new();

  /// <summary>
  ///   物品的附魔价值
  ///   由具体子类实现，通常基于附魔等级和对应的乘数计算
  /// </summary>
  public abstract int Value { get; }

  /// <summary>
  ///   将当前附魔物品与另一个可附魔物品合并，返回合并后的新物品
  ///   合并规则：
  ///   1. 相同附魔会取最高等级，若等级相同则在不超过最大等级的前提下+1
  ///   2. 不同附魔会合并到结果中
  ///   3. 成本计算基于双方铁砧使用次数和附魔等级、乘数
  ///   4. 新物品的铁砧使用次数为双方最大值+1
  /// </summary>
  /// <param name="other">待合并的另一个可附魔物品</param>
  /// <returns>合并后生成的新附魔物品</returns>
  public IEnchantable Merge(IEnchantable other)
  {
    var target = CreateInstance();
    var cost = (1 << AnvilUseCount) - 1 + ((1 << other.AnvilUseCount) - 1);

    var leftMap = Enchantments.ToDictionary(x => x.Code);
    foreach (var rEnc in other.Enchantments)
      if (!leftMap.TryGetValue(rEnc.Code, out var lEnc)) {
        cost += rEnc.Level * rEnc.BookMultiplier;
        target.Enchantments.Add(rEnc);
      }
      else {
        var newEncLevel = rEnc.Level == lEnc.Level
          ? Math.Min(rEnc.Level + 1, rEnc.MaxLevel)
          : Math.Max(rEnc.Level, lEnc.Level);

        cost += newEncLevel * lEnc.BookMultiplier;
        target.Enchantments.Add(lEnc with { Level = newEncLevel });
        leftMap.Remove(rEnc.Code);
      }

    target.Enchantments.AddRange(leftMap.Values);
    target.Cost = cost;
    target.AnvilUseCount = Math.Max(AnvilUseCount, other.AnvilUseCount) + 1;
    return target;
  }

  /// <summary>
  ///   创建当前类的实例（工厂方法）
  ///   由具体子类实现，用于在合并操作时创建新的实例对象
  /// </summary>
  /// <returns>当前抽象类的具体子类实例</returns>
  protected abstract AbstractEnchant CreateInstance();
}